﻿
using Xacml.Core;
using System;
using System.Collections;
using System.IO;
using System.Reflection;
using System.Xml;
using System.Xml.Schema;

namespace Xacml.Core.Context
{
  public class ContextDocumentReadWrite
  {
    private bool _isValidDocument = true;
    private Hashtable _namespaces = new Hashtable();
    public const string XACML_1_0_CONTEXT_SCHEMA_RESOURCE_NAME = "Xacml.Core.Schemas.cs-xacml-schema-context-01.xsd";
    public const string XACML_2_0_CONTEXT_SCHEMA_RESOURCE_NAME = "Xacml.Core.Schemas.access_control-xacml-2.0-context-schema-cd-01.xsd";
    private RequestElementReadWrite _request;
    private ResponseElement _response;
    private string _xmlString;
    private XmlDocument _xmlDocument;
    private XmlNamespaceManager _xmlNamespaceManager;

    public bool IsValidDocument
    {
      get
      {
        return this._isValidDocument;
      }
    }

    public virtual RequestElementReadWrite Request
    {
      get
      {
        return this._request;
      }
      set
      {
        this._request = value;
      }
    }

    public ResponseElement Response
    {
      get
      {
        return this._response;
      }
      set
      {
        this._response = value;
      }
    }

    public XmlDocument XmlDocument
    {
      get
      {
        if (this._xmlDocument == null)
        {
          this._xmlDocument = new XmlDocument();
          this._xmlDocument.LoadXml(this._xmlString);
        }
        return this._xmlDocument;
      }
    }

    public XmlNamespaceManager XmlNamespaceManager
    {
      get
      {
        return this._xmlNamespaceManager;
      }
    }

    public Hashtable Namespaces
    {
      get
      {
        return this._namespaces;
      }
    }

    public ContextDocumentReadWrite()
    {
    }

    public ContextDocumentReadWrite(XmlReader reader, XacmlVersion schemaVersion)
    {
      do
        ;
      while (reader.Read() && reader.NodeType != XmlNodeType.Element);
      this._xmlString = reader.ReadOuterXml();
      XmlValidatingReader validatingReader = new XmlValidatingReader((XmlReader) new XmlTextReader((TextReader) new StringReader(this._xmlString)));
      switch (schemaVersion)
      {
        case XacmlVersion.Version10:
        case XacmlVersion.Version11:
          validatingReader.Schemas.Add("urn:oasis:names:tc:xacml:1.0:policy", (XmlReader) new XmlTextReader(Assembly.GetExecutingAssembly().GetManifestResourceStream("Xacml.Core.Schemas.cs-xacml-schema-policy-01.xsd")));
          validatingReader.Schemas.Add("urn:oasis:names:tc:xacml:1.0:context", (XmlReader) new XmlTextReader(Assembly.GetExecutingAssembly().GetManifestResourceStream("Xacml.Core.Schemas.cs-xacml-schema-context-01.xsd")));
          break;
        case XacmlVersion.Version20:
          validatingReader.Schemas.Add("urn:oasis:names:tc:xacml:2.0:policy", (XmlReader) new XmlTextReader(Assembly.GetExecutingAssembly().GetManifestResourceStream("Xacml.Core.Schemas.access_control-xacml-2.0-policy-schema-cd-01.xsd")));
          validatingReader.Schemas.Add("urn:oasis:names:tc:xacml:2.0:context", (XmlReader) new XmlTextReader(Assembly.GetExecutingAssembly().GetManifestResourceStream("Xacml.Core.Schemas.access_control-xacml-2.0-context-schema-cd-01.xsd")));
          break;
        default:
          throw new ArgumentException(Resource.ResourceManager[Resource.MessageKey.exc_invalid_version_parameter_value], "version");
      }
      validatingReader.ValidationEventHandler += new ValidationEventHandler(this.vreader_ValidationEventHandler);
      while (validatingReader.Read())
      {
        if (validatingReader.HasAttributes)
        {
          while (validatingReader.MoveToNextAttribute())
          {
            if (validatingReader.LocalName == "xmlns")
              this._namespaces.Add((object) validatingReader.Prefix, (object) validatingReader.Value);
            else if (validatingReader.Prefix == "xmlns")
              this._namespaces.Add((object) validatingReader.LocalName, (object) validatingReader.Value);
          }
          validatingReader.MoveToElement();
        }
        switch (validatingReader.LocalName)
        {
          case "Request":
            this._request = new RequestElementReadWrite((XmlReader) validatingReader, schemaVersion);
            continue;
          case "Response":
            this._response = new ResponseElement((XmlReader) validatingReader, schemaVersion);
            continue;
          default:
            continue;
        }
      }
    }

    public void AddNamespaces(IDictionary namespaces)
    {
      this._xmlNamespaceManager = new XmlNamespaceManager(this._xmlDocument.NameTable);
      foreach (string prefix in (IEnumerable) namespaces.Keys)
        this._xmlNamespaceManager.AddNamespace(prefix, (string) namespaces[(object) prefix]);
    }

    private void vreader_ValidationEventHandler(object sender, ValidationEventArgs e)
    {
      Console.WriteLine(e.Message);
      Console.WriteLine();
      this._isValidDocument = false;
    }

    public void WriteRequestDocument(XmlWriter writer)
    {
      if (this._request == null)
        return;
      this._request.WriteDocument(writer, this._namespaces);
    }
  }
}
